/*
 * This program (in conjunction to send) illustrates 
 * the use of a chain of two triggers. In particular, the 
 * receiver inserts triggers (id, id_a) and (id_a, R), while
 * the sender sends packets to id.
 * Usage:
 * > recv_private_trigger_chain <cfg_file.xml>
 * > send_private_id  <cfg_file.xml>
 */ 

#include <stdio.h>

#include "i3.h"
#include "i3_client_api.h"
#include "utils.h"

/* callbacks */
void receive_payload(cl_trigger *t, void *data, void *fun_ctx)
{
  long seq;
    
  cl_buf* clb = (cl_buf *) data;
  if (clb->data_len) {
    seq = ntohl(*((long *)(clb->data)));
    printf("recv. seq. #: %ld \n", seq);
  }
}

void constraint_failed(cl_trigger *t, void *data, void *fun_ctx)
{
  printf("Trigger constraint failed\n");
}
void trigger_inserted(cl_trigger *t, void *data, void *fun_ctx)
{
  printf("Trigger inserted\n");
}

void trigger_failure(cl_trigger *t, void *data, void *fun_ctx)
{
  printf("Trigger failed\n");

  /* reinsert trigger */
  cl_insert_trigger(t, 0);
}

int i3_main_loop(char *cfg_file)
{
  ID id, ida;
  cl_trigger *t1, *t;
  Key key;

  /* initialize context */
  cl_init(cfg_file);

  /* 
   * Create and insert triggers (id, ida), and (ida, R), respectively.
   * All triggers are r-constrained (right constrained) 
   */
  init_id_fromstr(&id, "this is a test id");
  init_id_fromstr(&ida, "this is another test id");

  /* Note: ida will be updated as ida.key = h_r(id.key) */
  t1 = cl_create_trigger_id(&id, ID_LEN_BITS, &ida, 
			    CL_TRIGGER_CFLAG_R_CONSTRAINT);
  /* Note: */
  t  = cl_create_trigger(&ida, ID_LEN_BITS, &key, 
			 CL_TRIGGER_CFLAG_R_CONSTRAINT);

  /* associate callbacks with the inserted trigger */
  cl_register_trigger_callback(t, CL_CBK_TRIGGER_CONSTRAINT_FAILED, 
			       constraint_failed, NULL);
  cl_register_trigger_callback(t, CL_CBK_RECEIVE_PAYLOAD, 
			       receive_payload, NULL);
  cl_register_trigger_callback(t, CL_CBK_TRIGGER_INSERTED, 
			       trigger_inserted, NULL);
  cl_register_trigger_callback(t, CL_CBK_TRIGGER_REFRESH_FAILED, 
			       trigger_failure, NULL);

  /* insert triggers */
  cl_insert_trigger(t, 0);
  cl_insert_trigger(t1, 0);
  
  /* loop forever */
  cl_loop();

  /* remove & destroy trigger */
  cl_destroy_trigger(t);
  cl_destroy_trigger(t1);

  /* destroy context */
  cl_exit();
}


int main(int argc, char **argv)
{
  if (argc != 2) {
    printf("%s <cfg_file.xml>\n", argv[0]);
    exit(-1);
  }
  
  i3_main_loop(argv[1]);
  return -1;
}

